// FullQuoteDlg.cpp : implementation file
//

#include "stdafx.h"
#include "LightspeedTraderAPIDemo.h"
#include "FullQuoteDlg.h"

enum FQ_STATIC_VALUES {
	SYMBOL,
	EXCHANGE,
	PRIMARY_MARKET,
	IS_LISTED,
	MARGIN_REQUIREMENT,
	COMPANY_NAME,

	END_OF_STATIC_VALUES
};

enum FQ_L1_VALUES {
	LAST_PRICE = END_OF_STATIC_VALUES,
	LAST_SIZE,
	LAST_TIME,
	VOLUME,
	BID,
	ASK,
	BID_SIZE,
	ASK_SIZE,

	END_OF_L1_VALUES
};

enum FQ_L2_VALUES {
	VISIBLE_BID = END_OF_L1_VALUES,
	VISIBLE_ASK,
	VISIBLE_BID_SIZE,
	VISIBLE_ASK_SIZE,

	END_OF_L2_VALUES
};

enum BEST_QUOTE_VALUES {
	QT_BLANK_LINE = END_OF_L2_VALUES,
	QT_BEST_QUOTE_STRING_LINE,

	QT_SOURCE,
	QT_MARKET,
	QT_PRICE,
	QT_SIZE,
	QT_TIME,
	QT_CONDITION,
	QT_IS_ECN,
	QT_IS_DIRECT,
	QT_IS_CLOSED,
	QT_IS_CROSSED,

	END_OF_BEST_QT_VALUES
};

enum BEST_L2_QUOTE_VALUES {
	L2_BLANK_LINE = END_OF_BEST_QT_VALUES,
	L2_BEST_QUOTE_STRING_LINE,

	L2_SOURCE,
	L2_MARKET,
	L2_PRICE,
	L2_SIZE,
	L2_TIME,
	L2_CONDITION,
	L2_IS_ECN,
	L2_IS_DIRECT,
	L2_IS_CLOSED,
	L2_IS_CROSSED,

	END_OF_BEST_L2_VALUES
};

enum BEST_ECN_QUOTE_VALUES {
	ECN_BLANK_LINE = END_OF_BEST_L2_VALUES,
	ECN_BEST_QUOTE_STRING_LINE,

	ECN_SOURCE,
	ECN_MARKET,
	ECN_PRICE,
	ECN_SIZE,
	ECN_TIME,
	ECN_CONDITION,
	ECN_IS_ECN,
	ECN_IS_DIRECT,
	ECN_IS_CLOSED,
	ECN_IS_CROSSED,

	END_OF_BEST_ECN_VALUES
};

const int MAX_TRADES_DISPLAYED = 15;

// FullQuoteDlg dialog

IMPLEMENT_DYNAMIC(FullQuoteDlg, CModelessDialog)

FullQuoteDlg::FullQuoteDlg(CWnd* pParent /*=NULL*/)
	: CModelessDialog(FullQuoteDlg::IDD, pParent)
	, m_SymbolEdit(CEdit())
	, m_MarketCombo(CComboBox())
	, m_FQDataListCtrl(CListCtrl())
	, m_BookListCtrl(CListCtrl())
	, m_TradesListCtrl(CListCtrl())
	, m_BookDispCombo(CComboBox())
	, m_BookSideDisp(DISP_BID)
	, fullQuote(NULL)
	, bestQuote(NULL)
	, bestL2Quote(NULL)
	, bestECNQuote(NULL)
	, bestQuoteMarket("NSDQ")
	, m_BookDisp(DISP_MERGED)
	, m_iNextTradeRow(0)
	, m_Linked(false)
{
	SetAPIFunctions();
}

FullQuoteDlg::~FullQuoteDlg()
{
	if (fullQuote)
	{
		fullQuote->L_Detach(this);
		L_DestroyFullQuote(fullQuote);
		fullQuote = NULL;
	}

	if (bestQuote)
	{
		bestQuote = NULL;
	}
}

BOOL FullQuoteDlg::Create(CWnd *pParentWnd /*= CWnd::FromHandle(L_GetMainWnd())*/)
{
	return __super::Create(FullQuoteDlg::IDD, pParentWnd);
}

void FullQuoteDlg::DoDataExchange(CDataExchange* pDX)
{
	__super::DoDataExchange(pDX);

	DDX_Control(pDX, IDC_SYMBOLEDIT, m_SymbolEdit);
	DDX_Control(pDX, IDC_FQDATALIST, m_FQDataListCtrl);
	DDX_Control(pDX, IDC_FQBOOKLIST, m_BookListCtrl);
	DDX_Control(pDX, IDC_BOOKSIDECOMBO, m_BookSideCombo);
	DDX_Control(pDX, IDC_MARKETCOMBO, m_MarketCombo);
	DDX_Control(pDX, IDC_BOOKDISPCOMBO, m_BookDispCombo);
	DDX_Control(pDX, IDC_FQTRADESLIST, m_TradesListCtrl);
}

BOOL FullQuoteDlg::OnInitDialog()
{
	__super::OnInitDialog();

	ResizeControls();

	DWORD style = m_FQDataListCtrl.GetExtendedStyle();
	style |= LVS_EX_FULLROWSELECT;
	style |= LVS_EX_GRIDLINES;
	style |= LVS_EX_DOUBLEBUFFER;
	m_FQDataListCtrl.SetExtendedStyle(style);

	m_FQDataListCtrl.InsertColumn(0,"API Function", LVCFMT_LEFT, 130, 0);
	m_FQDataListCtrl.InsertColumn(1,"Value", LVCFMT_LEFT, 110, 1);
	InitializeDataCtrlRows();

	style = m_BookListCtrl.GetExtendedStyle();
	style |= LVS_EX_FULLROWSELECT;
	style |= LVS_EX_GRIDLINES;
	style |= LVS_EX_DOUBLEBUFFER;
	m_BookListCtrl.SetExtendedStyle(style);

	m_BookListCtrl.InsertColumn(0, "Source", LVCFMT_LEFT, 50, 0);
	m_BookListCtrl.InsertColumn(1, "Market", LVCFMT_LEFT, 55, 1);
	m_BookListCtrl.InsertColumn(2, "Price", LVCFMT_RIGHT, 55, 2);
	m_BookListCtrl.InsertColumn(3, "Size", LVCFMT_RIGHT, 60, 3);
	m_BookListCtrl.InsertColumn(4, "Time", LVCFMT_LEFT, 70, 4);
	m_BookListCtrl.InsertColumn(5, "Condition", LVCFMT_LEFT, 60, 5);
	m_BookListCtrl.InsertColumn(6, "isECN", LVCFMT_LEFT, 50, 6);
	m_BookListCtrl.InsertColumn(7, "isDirect", LVCFMT_LEFT, 50, 7);
	m_BookListCtrl.InsertColumn(8, "isClosed", LVCFMT_LEFT, 50, 8);
	m_BookListCtrl.InsertColumn(9, "isCrossed", LVCFMT_LEFT, 50, 9);

	style = m_TradesListCtrl.GetExtendedStyle();
	style |= LVS_EX_FULLROWSELECT;
	style |= LVS_EX_GRIDLINES;
	style |= LVS_EX_DOUBLEBUFFER;
	m_TradesListCtrl.SetExtendedStyle(style);

	m_TradesListCtrl.InsertColumn(0, "Price", LVCFMT_RIGHT, 55, 0);
	m_TradesListCtrl.InsertColumn(1, "Volume", LVCFMT_RIGHT, 55, 1);
	m_TradesListCtrl.InsertColumn(2, "Time", LVCFMT_LEFT, 50, 2);
	m_TradesListCtrl.InsertColumn(3, "Market", LVCFMT_LEFT, 50, 3);
	m_TradesListCtrl.InsertColumn(4, "Sale Condition", LVCFMT_LEFT, 50, 4);

	m_BookSideCombo.InsertString(DISP_BID, "Bid");
	m_BookSideCombo.InsertString(DISP_ASK, "Ask");
	m_BookSideCombo.SetCurSel(DISP_BID);

	m_BookDispCombo.InsertString(DISP_MERGED, "Merged");
	m_BookDispCombo.InsertString(DISP_L2_NASDAQ, "L2 Nasdaq");
	m_BookDispCombo.InsertString(DISP_L2_NATIONAL, "L2 National");
	m_BookDispCombo.InsertString(DISP_ECN, "ECN");
	m_BookDispCombo.SetCurSel(DISP_MERGED);

	m_MarketCombo.SetWindowText(bestQuoteMarket);

	L_AttachToAppNotifier(this);

	return TRUE;
}

void FullQuoteDlg::OnOK()
{
	//Update fullQuote from symbol
	CString symbol;
	m_SymbolEdit.GetWindowText(symbol);
	symbol.Trim();
	if (! symbol.IsEmpty())
	{
		if (!fullQuote || strcmp(symbol.GetBuffer(), fullQuote->L_Symbol()) != 0)
		{
			SetSymbol(symbol.GetBuffer());

			if (m_Linked)
			{
				L_SetFocusedSymbol(symbol.GetBuffer());
			}
		}
	}

	//Update Best quote from market and bid/ask
	m_MarketCombo.GetWindowText(bestQuoteMarket);
	bestQuoteMarket.Trim();
	UpdateBestQuotes();

	UpdateBook();
}

void FullQuoteDlg::SetSymbol(const char *symbol)
{
	if (fullQuote)
	{
		fullQuote->L_Detach(this);
		L_DestroyFullQuote(fullQuote);
	}

	fullQuote = L_CreateFullQuote(symbol);
	fullQuote->L_Attach(this);
		
	UpdateStaticFQData();
	UpdateMarketComboBox();
	UpdateL1FQData();
	UpdateL2FQData();
	UpdateBook();
	InsertInitialTrades();
}

void FullQuoteDlg::InitializeDataCtrlRows()
{
	for (int i = 0; i < END_OF_BEST_ECN_VALUES; ++i)
	{
		m_FQDataListCtrl.InsertItem(i,APIFunctions[i]);
	}
}

void FullQuoteDlg::UpdateStaticFQData()
{
	m_FQDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = 0; i < END_OF_STATIC_VALUES; ++i)
	{
		UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, GetTextForFunction(i));
	}
	m_FQDataListCtrl.SetRedraw(TRUE);
}

void FullQuoteDlg::UpdateL1FQData()
{
	m_FQDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_STATIC_VALUES; i < END_OF_L1_VALUES; ++i)
	{
		UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, GetTextForFunction(i));
	}
	m_FQDataListCtrl.SetRedraw(TRUE);
}

void FullQuoteDlg::UpdateL2FQData()
{
	m_FQDataListCtrl.SetRedraw(FALSE); //disable redraw to reduce control flickering
	for (int i = END_OF_L1_VALUES; i < END_OF_L2_VALUES; ++i)
	{
		UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, GetTextForFunction(i));
	}
	m_FQDataListCtrl.SetRedraw(TRUE);
}

void FullQuoteDlg::UpdateBook()
{
	bool iteratorsSet = false;
	quote_iterator it, itend;

	if (fullQuote)
	{
		switch(m_BookDisp)
		{
		case DISP_MERGED:
			{
				switch (m_BookSideDisp)
				{
				case DISP_BID:
					it = fullQuote->bids_begin();
					itend = fullQuote->bids_end();
					iteratorsSet = true;
					break;
				case DISP_ASK:
					it = fullQuote->asks_begin();
					itend = fullQuote->asks_end();
					iteratorsSet = true;
					break;
				}
			}
			break;
		case DISP_L2_NASDAQ:
			{
				switch (m_BookSideDisp)
				{
				case DISP_BID:
					it = fullQuote->l2_bids_begin(L_L2Source::Nasdaq);
					itend = fullQuote->l2_bids_end(L_L2Source::Nasdaq);
					iteratorsSet = true;
					break;
				case DISP_ASK:
					it = fullQuote->l2_asks_begin(L_L2Source::Nasdaq);
					itend = fullQuote->l2_asks_end(L_L2Source::Nasdaq);
					iteratorsSet = true;
					break;
				}
			}
			break;
		case DISP_L2_NATIONAL:
			{
				switch (m_BookSideDisp)
				{
				case DISP_BID:
					it = fullQuote->l2_bids_begin(L_L2Source::National);
					itend = fullQuote->l2_bids_end(L_L2Source::National);
					iteratorsSet = true;
					break;
				case DISP_ASK:
					it = fullQuote->l2_asks_begin(L_L2Source::National);
					itend = fullQuote->l2_asks_end(L_L2Source::National);
					iteratorsSet = true;
					break;
				}
			}
			break;
		case DISP_ECN:
			{
				switch (m_BookSideDisp)
				{
				case DISP_BID:
					it = fullQuote->ecn_bids_begin(bestQuoteMarket.GetBuffer());
					itend = fullQuote->ecn_bids_end(bestQuoteMarket.GetBuffer());
					iteratorsSet = true;
					break;
				case DISP_ASK:
					it = fullQuote->ecn_asks_begin(bestQuoteMarket.GetBuffer());
					itend = fullQuote->ecn_asks_end(bestQuoteMarket.GetBuffer());
					iteratorsSet = true;
					break;
				}
			}
			break;
		}
	}

	if (iteratorsSet)
	{
		int i = 0;
		for(;it != itend; ++it, ++i)
		{
			CString text;
			text = it->L_Source();
			if (m_BookListCtrl.GetItemCount() > i) //if row exist change values
			{
				UpdateListCtrlCellText(m_BookListCtrl, i, 0, text);
			}
			else //insert row
			{
				m_BookListCtrl.InsertItem(i,text);
			}

			text = it->L_MMID();
			UpdateListCtrlCellText(m_BookListCtrl, i, 1, text);

			text.Format("%.2f", it->L_Price());
			UpdateListCtrlCellText(m_BookListCtrl, i, 2, text);

			text.Format("%d", it->L_Size());
			UpdateListCtrlCellText(m_BookListCtrl, i, 3, text);

			text.Format("%d", it->L_Time());
			UpdateListCtrlCellText(m_BookListCtrl, i, 4, text);

			text = it->L_Condition();
			UpdateListCtrlCellText(m_BookListCtrl, i, 5, text);

			UpdateListCtrlCellText(m_BookListCtrl, i, 6, (it->L_IsECN() ? "Yes" : "No"));
			UpdateListCtrlCellText(m_BookListCtrl, i, 7, (it->L_IsDirect() ? "Yes" : "No"));
			UpdateListCtrlCellText(m_BookListCtrl, i, 8, (it->L_IsClosed() ? "Yes" : "No"));
			UpdateListCtrlCellText(m_BookListCtrl, i, 9, (it->L_IsCrossed() ? "Yes" : "No"));
		}

		//Delete extra rows
		while (i < m_BookListCtrl.GetItemCount())
		{
			m_BookListCtrl.DeleteItem(i);
		}
	}
}

void FullQuoteDlg::UpdateBestQuotes()
{
	if (!fullQuote)
		return;

	m_FQDataListCtrl.SetRedraw(FALSE);

	bestQuote = fullQuote->L_BestQuote(m_BookSideDisp == DISP_BID, bestQuoteMarket.GetBuffer());
	if (bestQuote)
	{
		for (int i = QT_BEST_QUOTE_STRING_LINE + 1; i < END_OF_BEST_QT_VALUES; ++i)
		{
			UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, GetTextForFunction(i));
		}
	}
	else //clear any existing data
	{
		for (int i = QT_BEST_QUOTE_STRING_LINE + 1; i < END_OF_BEST_QT_VALUES; ++i)
		{
			UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, "");
		}
	}

	bestL2Quote = fullQuote->L_BestL2Quote(m_BookSideDisp == DISP_BID, bestQuoteMarket.GetBuffer());
	if (bestL2Quote)
	{
		for (int i = L2_BEST_QUOTE_STRING_LINE + 1; i < END_OF_BEST_L2_VALUES; ++i)
		{
			UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, GetTextForFunction(i));
		}
	}
	else //clear any existing data
	{
		for (int i = L2_BEST_QUOTE_STRING_LINE + 1; i < END_OF_BEST_L2_VALUES; ++i)
		{
			UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, "");
		}
	}

	bestECNQuote = fullQuote->L_BestECNQuote(m_BookSideDisp == DISP_BID, bestQuoteMarket.GetBuffer());
	if (bestECNQuote)
	{
		for (int i = ECN_BEST_QUOTE_STRING_LINE + 1; i < END_OF_BEST_ECN_VALUES; ++i)
		{
			UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, GetTextForFunction(i));
		}
	}
	else //clear any existing data
	{
		for (int i = ECN_BEST_QUOTE_STRING_LINE + 1; i < END_OF_BEST_ECN_VALUES; ++i)
		{
			UpdateListCtrlCellText(m_FQDataListCtrl, i, 1, "");
		}
	}

	m_FQDataListCtrl.SetRedraw(TRUE);
}

void FullQuoteDlg::UpdateListCtrlCellText(CListCtrl &ctrl, int nItem, int nSubItem, CString updateText)
{
	CString curText;
	curText = ctrl.GetItemText(nItem, nSubItem);
	if (curText != updateText)
	{
		ctrl.SetItemText(nItem, nSubItem, updateText);
	}
}

void FullQuoteDlg::UpdateMarketComboBox()
{
	if (fullQuote)
	{
		CString curString;
		m_MarketCombo.GetWindowText(curString);
		while (m_MarketCombo.GetCount() > 0)
		{
			m_MarketCombo.DeleteString(0);
		}

		for (direct_book_iterator it(fullQuote->ecn_names_begin()), itend(fullQuote->ecn_names_end());
			it != itend; ++it)
		{
			m_MarketCombo.AddString(*it);
		}
		m_MarketCombo.SetWindowText(curString);
	}
}

void FullQuoteDlg::InsertInitialTrades()
{
	int tradesInserted = 0;
	trade_iterator it = fullQuote->trades_begin();
	trade_iterator itend = fullQuote->trades_end();

	m_TradesListCtrl.SetRedraw(FALSE);
	for (; it != itend && tradesInserted < MAX_TRADES_DISPLAYED; ++it, ++tradesInserted)
	{
		InsertNewTrade
			( it->L_Price()
			, it->L_Volume()
			, it->L_Market()
			, it->L_SaleCondition()
			, it->L_Time()
			);
	}
	m_TradesListCtrl.SetRedraw(TRUE);
}

void FullQuoteDlg::InsertNewTrade(double price, long long volume, char const *market, char saleCondition, time_t time)
{
	CString text;

	if (m_iNextTradeRow == MAX_TRADES_DISPLAYED)
	{
		m_iNextTradeRow = 0;
		m_TradesListCtrl.DeleteItem(MAX_TRADES_DISPLAYED-1);
	}

	text.Format("%.2f", price);
	if (m_iNextTradeRow == 0 || m_TradesListCtrl.GetItemCount() <= m_iNextTradeRow)
	{
		m_TradesListCtrl.InsertItem(m_iNextTradeRow, text);
	}
	else
	{
		UpdateListCtrlCellText(m_TradesListCtrl,m_iNextTradeRow, 0, text);
	}

	text.Format("%d", volume);
	UpdateListCtrlCellText(m_TradesListCtrl, m_iNextTradeRow, 1, text);

	text.Format("%d", time);
	UpdateListCtrlCellText(m_TradesListCtrl, m_iNextTradeRow, 2, text);

	text = market;
	UpdateListCtrlCellText(m_TradesListCtrl, m_iNextTradeRow, 3, text);

	text = saleCondition;
	UpdateListCtrlCellText(m_TradesListCtrl, m_iNextTradeRow, 4, text);

	//highlight current trade
	m_TradesListCtrl.SetItemState(m_iNextTradeRow,LVIS_SELECTED, LVIS_SELECTED);
	//m_TradesListCtrl.SetSelectionMark(m_iNextTradeRow);
	m_iNextTradeRow++;
}

void FullQuoteDlg::SetAPIFunctions()
{
	//clear APIFunction array
	memset(APIFunctions,NULL,sizeof(APIFunctions));

	strcpy_s(APIFunctions[SYMBOL], "Symbol");
	strcpy_s(APIFunctions[EXCHANGE], "Exchange");
	strcpy_s(APIFunctions[PRIMARY_MARKET], "Primary Market");
	strcpy_s(APIFunctions[IS_LISTED], "Is Listed");
	strcpy_s(APIFunctions[MARGIN_REQUIREMENT], "Margin Requirement");
	strcpy_s(APIFunctions[COMPANY_NAME], "Company Name");
	strcpy_s(APIFunctions[LAST_PRICE], "Last Price");
	strcpy_s(APIFunctions[LAST_SIZE], "Last Size");
	strcpy_s(APIFunctions[LAST_TIME], "Last Time");
	strcpy_s(APIFunctions[VOLUME], "Volume");
	strcpy_s(APIFunctions[BID], "Bid");
	strcpy_s(APIFunctions[ASK], "Ask");
	strcpy_s(APIFunctions[BID_SIZE], "Bid Size");
	strcpy_s(APIFunctions[ASK_SIZE], "Ask Size");
	strcpy_s(APIFunctions[VISIBLE_BID], "Visible Bid");
	strcpy_s(APIFunctions[VISIBLE_ASK], "Visible Ask");
	strcpy_s(APIFunctions[VISIBLE_BID_SIZE], "Visible Bid Size");
	strcpy_s(APIFunctions[VISIBLE_ASK_SIZE], "Visible Ask Size");
	strcpy_s(APIFunctions[QT_BEST_QUOTE_STRING_LINE], "Best Quote");
	strcpy_s(APIFunctions[QT_SOURCE], "Source");
	strcpy_s(APIFunctions[QT_MARKET], "Market");
	strcpy_s(APIFunctions[QT_PRICE], "Price");
	strcpy_s(APIFunctions[QT_SIZE], "Size");
	strcpy_s(APIFunctions[QT_TIME], "Time");
	strcpy_s(APIFunctions[QT_CONDITION], "Condition");
	strcpy_s(APIFunctions[QT_IS_ECN], "Is ECN");
	strcpy_s(APIFunctions[QT_IS_DIRECT], "Is Direct");
	strcpy_s(APIFunctions[QT_IS_CLOSED], "Is Closed");
	strcpy_s(APIFunctions[QT_IS_CROSSED], "Is Crossed");
	strcpy_s(APIFunctions[L2_BEST_QUOTE_STRING_LINE], "Best L2 Quote");
	strcpy_s(APIFunctions[L2_SOURCE], APIFunctions[QT_SOURCE]);
	strcpy_s(APIFunctions[L2_MARKET], APIFunctions[QT_MARKET]);
	strcpy_s(APIFunctions[L2_PRICE], APIFunctions[QT_PRICE]);
	strcpy_s(APIFunctions[L2_SIZE], APIFunctions[QT_SIZE]);
	strcpy_s(APIFunctions[L2_TIME], APIFunctions[QT_TIME]);
	strcpy_s(APIFunctions[L2_CONDITION], APIFunctions[QT_CONDITION]);
	strcpy_s(APIFunctions[L2_IS_ECN], APIFunctions[QT_IS_ECN]);
	strcpy_s(APIFunctions[L2_IS_DIRECT], APIFunctions[QT_IS_DIRECT]);
	strcpy_s(APIFunctions[L2_IS_CLOSED], APIFunctions[QT_IS_CLOSED]);
	strcpy_s(APIFunctions[L2_IS_CROSSED], APIFunctions[QT_IS_CROSSED]);
	strcpy_s(APIFunctions[ECN_BEST_QUOTE_STRING_LINE], "Best ECN Quote");
	strcpy_s(APIFunctions[ECN_SOURCE], APIFunctions[QT_SOURCE]);
	strcpy_s(APIFunctions[ECN_MARKET], APIFunctions[QT_MARKET]);
	strcpy_s(APIFunctions[ECN_PRICE], APIFunctions[QT_PRICE]);
	strcpy_s(APIFunctions[ECN_SIZE], APIFunctions[QT_SIZE]);
	strcpy_s(APIFunctions[ECN_TIME], APIFunctions[QT_TIME]);
	strcpy_s(APIFunctions[ECN_CONDITION], APIFunctions[QT_CONDITION]);
	strcpy_s(APIFunctions[ECN_IS_ECN], APIFunctions[QT_IS_ECN]);
	strcpy_s(APIFunctions[ECN_IS_DIRECT], APIFunctions[QT_IS_DIRECT]);
	strcpy_s(APIFunctions[ECN_IS_CLOSED], APIFunctions[QT_IS_CLOSED]);
	strcpy_s(APIFunctions[ECN_IS_CROSSED], APIFunctions[QT_IS_CROSSED]);
}

CString FullQuoteDlg::GetTextForFunction(int function)
{
	CString retString = "";
	switch (function)
	{
		//fullQuote source
	case SYMBOL:
		{
			retString = fullQuote->L_Symbol();
		}
		break;
	case EXCHANGE:
		{
			retString = fullQuote->L_Exchange();
		}
		break;
	case PRIMARY_MARKET:
		{
			retString = fullQuote->L_PrimaryMarket();
		}
		break;
	case IS_LISTED:
		{
			if (fullQuote->L_IsListed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case MARGIN_REQUIREMENT:
		{
			retString.Format("%.2f", fullQuote->L_MarginRequirement());
		}
		break;
	case COMPANY_NAME:
		{
			retString = fullQuote->L_CompanyName();
		}
		break;
	case LAST_PRICE:
		{
			retString.Format("%.2f", fullQuote->L_LastPrice());
		}
		break;
	case LAST_SIZE:
		{
			retString.Format("%d", fullQuote->L_LastSize());
		}
		break;
	case LAST_TIME:
		{
			retString.Format("%d", fullQuote->L_LastTime());
		}
		break;
	case VOLUME:
		{
			retString.Format("%d", fullQuote->L_Volume());
		}
		break;
	case BID:
		{
			retString.Format("%.2f", fullQuote->L_Bid());
		}
		break;
	case ASK:
		{
			retString.Format("%.2f", fullQuote->L_Ask());
		}
		break;
	case BID_SIZE:
		{
			retString.Format("%d", fullQuote->L_BidSize());
		}
		break;
	case ASK_SIZE:
		{
			retString.Format("%d", fullQuote->L_AskSize());
		}
		break;
	case VISIBLE_BID:
		{
			retString.Format("%.2f", fullQuote->L_VisibleBid());
		}
		break;
	case VISIBLE_ASK:
		{
			retString.Format("%.2f", fullQuote->L_VisibleAsk());
		}
		break;
	case VISIBLE_BID_SIZE:
		{
			retString.Format("%d", fullQuote->L_VisibleBidSize());
		}
		break;
	case VISIBLE_ASK_SIZE:
		{
			retString.Format("%d", fullQuote->L_VisibleAskSize());
		}
		break;

		//bestQuote source
	case QT_SOURCE:
		{
			retString = bestQuote->L_Source();
		}
		break;
	case QT_MARKET:
		{
			retString = bestQuote->L_MMID();
		}
		break;
	case QT_PRICE:
		{
			retString.Format("%.2f", bestQuote->L_Price());
		}
		break;
	case QT_SIZE:
		{
			retString.Format("%d", bestQuote->L_Size());
		}
		break;
	case QT_TIME:
		{
			retString.Format("%d", bestQuote->L_Time());
		}
		break;
	case QT_CONDITION:
		{
			retString = bestQuote->L_Condition();
		}
		break;
	case QT_IS_ECN:
		{
			if (bestQuote->L_IsECN())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case QT_IS_DIRECT:
		{
			if (bestQuote->L_IsDirect())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case QT_IS_CLOSED:
		{
			if (bestQuote->L_IsClosed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case QT_IS_CROSSED:
		{
			if (bestQuote->L_IsCrossed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;

		//bestL2Quote source
	case L2_SOURCE:
		{
			retString = bestL2Quote->L_Source();
		}
		break;
	case L2_MARKET:
		{
			retString = bestL2Quote->L_MMID();
		}
		break;
	case L2_PRICE:
		{
			retString.Format("%.2f", bestL2Quote->L_Price());
		}
		break;
	case L2_SIZE:
		{
			retString.Format("%d", bestL2Quote->L_Size());
		}
		break;
	case L2_TIME:
		{
			retString.Format("%d", bestL2Quote->L_Time());
		}
		break;
	case L2_CONDITION:
		{
			retString = bestL2Quote->L_Condition();
		}
		break;
	case L2_IS_ECN:
		{
			if (bestL2Quote->L_IsECN())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case L2_IS_DIRECT:
		{
			if (bestL2Quote->L_IsDirect())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case L2_IS_CLOSED:
		{
			if (bestL2Quote->L_IsClosed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case L2_IS_CROSSED:
		{
			if (bestL2Quote->L_IsCrossed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;

		//bestECNQuote source
	case ECN_SOURCE:
		{
			retString = bestECNQuote->L_Source();
		}
		break;
	case ECN_MARKET:
		{
			retString = bestECNQuote->L_MMID();
		}
		break;
	case ECN_PRICE:
		{
			retString.Format("%.2f", bestECNQuote->L_Price());
		}
		break;
	case ECN_SIZE:
		{
			retString.Format("%d", bestECNQuote->L_Size());
		}
		break;
	case ECN_TIME:
		{
			retString.Format("%d", bestECNQuote->L_Time());
		}
		break;
	case ECN_CONDITION:
		{
			retString = bestECNQuote->L_Condition();
		}
		break;
	case ECN_IS_ECN:
		{
			if (bestECNQuote->L_IsECN())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case ECN_IS_DIRECT:
		{
			if (bestECNQuote->L_IsDirect())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case ECN_IS_CLOSED:
		{
			if (bestECNQuote->L_IsClosed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	case ECN_IS_CROSSED:
		{
			if (bestECNQuote->L_IsCrossed())
			{
				retString = "Yes";
			}
			else
			{
				retString = "No";
			}
		}
		break;
	}
	return retString;
}

//L_Observer
void FullQuoteDlg::HandleMessage(L_Message const *pMsg)
{
	switch (pMsg->L_Type())
	{
	case L_MsgSymbolChanged::id:
		{
			if (m_Linked)
			{
				SetSymbol(pMsg->L_Symbol());
			}
		}
		break;
	case L_MsgL1::id:
	case L_MsgL1Change::id:
		{
			if (fullQuote && !strcmp(pMsg->L_Symbol(),fullQuote->L_Symbol()))
			{
				UpdateStaticFQData();
				UpdateL1FQData();
			}
			UpdateMarketComboBox();
		}
		break;
	case L_MsgL1Update::id:
		{
			if (fullQuote && !strcmp(pMsg->L_Symbol(), fullQuote->L_Symbol()))
			{
				UpdateL1FQData();
			}
		}
		break;
	case L_MsgL2::id:
		UpdateMarketComboBox();
	case L_MsgL2Refresh::id:
	case L_MsgL2Update::id:
	case L_MsgECN::id:
	case L_MsgECNUpdate::id:
		{
			if (fullQuote && !strcmp(pMsg->L_Symbol(), fullQuote->L_Symbol()))
			{
				UpdateL1FQData();
				UpdateL2FQData();
				UpdateBestQuotes();
				UpdateBook();
			}
		}
		break;
	case L_MsgTrade::id:
		{
			InsertInitialTrades();
		}
		break;
	case L_MsgTradeUpdate::id:
		{
			if (fullQuote && !strcmp(fullQuote->L_Symbol(), pMsg->L_Symbol()))
			{
				L_MsgTradeUpdate const *pMsgTU = static_cast<L_MsgTradeUpdate const *>(pMsg);
				InsertNewTrade
					( pMsgTU->L_Price()
					, pMsgTU->L_Volume()
					, pMsgTU->L_Market()
					, pMsgTU->L_SaleCondition()
					, pMsgTU->L_Time()
					);

				m_TradesListCtrl.Invalidate(FALSE);
			}
		}
		break;
	case L_MsgECNList::id:
		{
			UpdateMarketComboBox();
		}
		break;
	}
}

BEGIN_MESSAGE_MAP(FullQuoteDlg, CModelessDialog)
	ON_WM_SIZE()
	ON_CBN_SELCHANGE(IDC_MARKETCOMBO, OnCbnSelchangeMarketCombo)
	ON_CBN_SELCHANGE(IDC_BOOKSIDECOMBO, OnCbnSelchangeBookSideCombo)
	ON_CBN_SELCHANGE(IDC_BOOKDISPCOMBO, OnCbnSelchangeBookDispCombo)
	ON_COMMAND(ID_FILE_LINK ,OnFileLink)
END_MESSAGE_MAP()


// FullQuoteDlg message handlers

void FullQuoteDlg::OnSize(UINT nType, int cx, int cy)
{
	__super::OnSize(nType, cx, cy);

	ResizeControls();
}

void FullQuoteDlg::ResizeControls()
{
	if (m_hWnd 
		&& m_FQDataListCtrl.m_hWnd 
		&& m_BookListCtrl.m_hWnd 
		&& m_BookSideCombo.m_hWnd
		&& m_BookDispCombo.m_hWnd
		&& m_TradesListCtrl.m_hWnd)
	{
		//get the rect of all of the controls that need to be moved/resized
		RECT clientRect;
		GetClientRect(&clientRect);

		RECT dataRect;
		m_FQDataListCtrl.GetWindowRect(&dataRect);
		ScreenToClient(&dataRect);

		RECT l2Rect;
		m_BookListCtrl.GetWindowRect(&l2Rect);
		ScreenToClient(&l2Rect);

		RECT tradesRect;
		m_TradesListCtrl.GetWindowRect(&tradesRect);
		ScreenToClient(&tradesRect);

		RECT sideRect;
		m_BookSideCombo.GetWindowRect(&sideRect);
		ScreenToClient(&sideRect);

		RECT dispRect;
		m_BookDispCombo.GetWindowRect(&dispRect);
		ScreenToClient(&dispRect);

		//data rect is 1/4 the width
		dataRect.left = clientRect.left;
		dataRect.bottom = clientRect.bottom;
		dataRect.right = clientRect.right / 4;

		//l2 rect is 1/2 the width
		l2Rect.left = dataRect.right + 1;
		l2Rect.bottom = clientRect.bottom;
		l2Rect.right = l2Rect.left + (clientRect.right / 2);

		//trades rect is the remaining width
		tradesRect.left = l2Rect.right + 1;
		tradesRect.bottom = clientRect.bottom;
		tradesRect.right = clientRect.right;

		//side control will be lined up with l2 list
		sideRect.right = (sideRect.right - sideRect.left) + l2Rect.left;
		sideRect.left = l2Rect.left;

		int dispRectWidth = (dispRect.right - dispRect.left);
		dispRect.left = sideRect.right + 20; //space them 20 apart
		dispRect.right = (dispRect.left + dispRectWidth);

		m_FQDataListCtrl.MoveWindow(&dataRect);
		m_BookListCtrl.MoveWindow(&l2Rect);
		m_TradesListCtrl.MoveWindow(&tradesRect);
		m_BookSideCombo.MoveWindow(&sideRect);
		m_BookDispCombo.MoveWindow(&dispRect);
	}
}

void FullQuoteDlg::OnCbnSelchangeBookSideCombo()
{
	m_BookSideDisp = m_BookSideCombo.GetCurSel();
	UpdateBestQuotes();
	UpdateBook();
}

void FullQuoteDlg::OnCbnSelchangeMarketCombo()
{
	//Update Best quote from market and bid/ask
	m_MarketCombo.GetLBText(m_MarketCombo.GetCurSel(),bestQuoteMarket);
	bestQuoteMarket.Trim();
	UpdateBestQuotes();
	UpdateBook();
}

void FullQuoteDlg::OnCbnSelchangeBookDispCombo()
{
	m_BookDisp = m_BookDispCombo.GetCurSel();
	UpdateBook();
}

void FullQuoteDlg::OnFileLink()
{
	m_Linked = !m_Linked;

	CMenu *menu = GetMenu();	
	menu->CheckMenuItem(ID_FILE_LINK, (m_Linked ? MF_CHECKED : MF_UNCHECKED) );
	
	if (m_Linked)
	{
		SetSymbol(::L_GetFocusedSymbol());
	}
}